home *** CD-ROM | disk | FTP | other *** search
- /* This program simulates a constraint satisfaction
- neural network for choosing tic-tac-toe moves as
- described in Volume 2 of the PDP books. The
- network is presented a description of the board
- and chooses the best move subject to predefined
- constraints.
-
- It requires an EGA or CGA to display a Hinton diagram
- of the element activation levels.
-
- Author : Gary Andriotakis
- Compiler : Microsoft Quick C
- Date : 5 January 1989
- */
- #include<stdio.h>
- #include <stdio.h>
- #include <time.h>
- #include <graph.h>
- #define N 67
- #define GAIN 0.1
- #define SCALE 1.0/16.0
- static float w[N][N], bias[N], a[N], e[N];
- main()
- {
- int j,mark = -1,converged;
- time_t t;
- #ifdef DEBUG
- initialize(a,w,bias);
- #endif
- #ifndef DEBUG
- if(!_setvideomode(_ERESCOLOR))
- { printf("EGA required\n");
- exit(0);
- }
- srand((int)time(&t));
- drawboard();
- do
- {
- putmarkers(&e[9],mark);
- initialize();
- boxes(a,N);
- do
- { j = randint(N);
- update(j);
- boxes(a,j);
- converged = ((j < 9) && (a[j] > 0.9));
- } while(!converged && !kbhit());
- if(converged)
- mark = j;
- else
- mark = -1;
- } while(converged || (kbhit() && getch() != 27));
- _displaycursor(_GCURSORON);
- _setvideomode(_DEFAULTMODE);
- #endif
- }
-
- update(j)
- int j;
- { int i;
- float net;
-
- net = 0.0;
- for(i = 0; i < N; i++)
- net += w[i][j]*a[i];
- net += bias[j];
- net *= GAIN;
- net += e[j];
- if(net > 0.0)
- a[j] += net*(1.0 - a[j]);
- else
- a[j] += net*a[j];
- }
-
- initialize()
- { int i,j;
- /* initialize to zero */
- for(i = 0; i < N; i++)
- { a[i] = 0.0;
- bias[i] = 0.0;
- for(j = 0; j < N; j++)
- w[i][j] = 0.0;
- }
-
- for(i = 0; i < 9; i++)
- { /* inhibit responses from occupied squares */
- w[i+9][i] = -8.0;
- w[i+18][i] = -8.0;
- /* mutual inhibition to insure only one response */
- for(j = 0; j < 9; j++)
- w[i][j] = -2.;
- /* self excitation to excourage self growth */
- w[i][i] = 2.;
- }
- /* empty line detectors */
- for(i = 0; i < 3; i++)
- { w[i+9][27] = -1.0;
- w[i+18][27] = -1.0;
- w[27][i] = 1.0;
- w[i+12][28] = -1.0;
- w[i+21][28] = -1.0;
- w[28][i+3] = 1.0;
- w[i+15][29] = -1.0;
- w[i+24][29] = -1.0;
- w[29][i+6] = 1.0;
- w[9+4*i][30] = -1.0;
- w[18+4*i][30] = -1.0;
- w[30][4*i] = 1.0;
- w[11+2*i][31] = -1.0;
- w[20+2*i][31] = -1.0;
- w[31][2+2*i] = 1.0;
- w[9+3*i][32] = -1.0;
- w[18+3*i][32] = -1.0;
- w[32][3*i] = 1.0;
- w[10+3*i][33] = -1.0;
- w[19+3*i][33] = -1.0;
- w[33][1+3*i] = 1.0;
- w[11+3*i][34] = -1.0;
- w[20+3*i][34] = -1.0;
- w[34][2+3*i] = 1.0;
- }
- /* friendly doubleton detectors */
- for(i = 0; i < 3; i++)
- { w[i+9][35] = 1.0;
- w[i+18][35] = -2.0;
- w[35][i] = 5.0;
- w[i+12][36] = 1.0;
- w[i+21][36] = -2.0;
- w[36][i+3] = 5.0;
- w[i+15][37] = 1.0;
- w[i+24][37] = -2.0;
- w[37][i+6] = 5.0;
- w[9+4*i][38] = 1.0;
- w[18+4*i][38] = -2.0;
- w[38][4*i] = 5.0;
- w[11+2*i][39] = 1.0;
- w[20+2*i][39] = -2.0;
- w[39][2+2*i] = 5.0;
- w[9+3*i][40] = 1.0;
- w[18+3*i][40] = -2.0;
- w[40][3*i] = 5.0;
- w[10+3*i][41] = 1.0;
- w[19+3*i][41] = -2.0;
- w[41][1+3*i] = 5.0;
- w[11+3*i][42] = 1.0;
- w[20+3*i][42] = -2.0;
- w[42][2+3*i] = 5.0;
- }
- /* enemy doubleton detectors */
- for(i = 0; i < 3; i++)
- { w[i+9][43] = -2.0;
- w[i+18][43] = 1.0;
- w[43][i] = 1.0;
- w[i+12][44] = -2.0;
- w[i+21][44] = 1.0;
- w[44][i+3] = 1.0;
- w[i+15][45] = -2.0;
- w[i+24][45] = 1.0;
- w[45][i+6] = 1.0;
- w[9+4*i][46] = -2.0;
- w[18+4*i][46] = 1.0;
- w[46][4*i] = 1.0;
- w[11+2*i][47] = -2.0;
- w[20+2*i][47] = 1.0;
- w[47][2+2*i] = 1.0;
- w[9+3*i][48] = -2.0;
- w[18+3*i][48] = 1.0;
- w[48][3*i] = 1.0;
- w[10+3*i][49] = -2.0;
- w[19+3*i][49] = 1.0;
- w[49][1+3*i] = 1.0;
- w[11+3*i][50] = -2.0;
- w[20+3*i][50] = 1.0;
- w[50][2+3*i] = 1.0;
- }
- /* friendly singleton detectors */
- for(i = 0; i < 3; i++)
- { w[i+9][51] = 1.0;
- w[i+18][51] = -2.0;
- w[51][i] = 2.0;
- w[i+12][52] = 1.0;
- w[i+21][52] = -2.0;
- w[52][i+3] = 2.0;
- w[i+15][53] = 1.0;
- w[i+24][53] = -2.0;
- w[53][i+6] = 2.0;
- w[9+4*i][54] = 1.0;
- w[18+4*i][54] = -2.0;
- w[54][4*i] = 2.0;
- w[11+2*i][55] = 1.0;
- w[20+2*i][55] = -2.0;
- w[55][2+2*i] = 2.0;
- w[9+3*i][56] = 1.0;
- w[18+3*i][56] = -2.0;
- w[56][3*i] = 2.0;
- w[10+3*i][57] = 1.0;
- w[19+3*i][57] = -2.0;
- w[57][1+3*i] = 2.0;
- w[11+3*i][58] = 1.0;
- w[20+3*i][58] = -2.0;
- w[58][2+3*i] = 2.0;
- }
- /* enemy singleton detectors */
- for(i = 0; i < 3; i++)
- { w[i+9][59] = -2.0;
- w[i+18][59] = 1.0;
- w[59][i] = 2.0;
- w[i+12][60] = -2.0;
- w[i+21][60] = 1.0;
- w[60][i+3] = 2.0;
- w[i+15][61] = -2.0;
- w[i+24][61] = 1.0;
- w[61][i+6] = 2.0;
- w[9+4*i][62] = -2.0;
- w[18+4*i][62] = 1.0;
- w[62][4*i] = 2.0;
- w[11+2*i][63] = -2.0;
- w[20+2*i][63] = 1.0;
- w[63][2+2*i] = 2.0;
- w[9+3*i][64] = -2.0;
- w[18+3*i][64] = 1.0;
- w[64][3*i] = 2.0;
- w[10+3*i][65] = -2.0;
- w[19+3*i][65] = 1.0;
- w[65][1+3*i] = 2.0;
- w[11+3*i][66] = -2.0;
- w[20+3*i][66] = 1.0;
- w[66][2+3*i] = 2.0;
- }
- /* biases */
- for(i = 0; i < 9; i++)
- bias[i] = 0.0625;
- for(i = 0; i < 8; i++)
- { bias[i+27] = 0.5;
- bias[i+35] = -1.5;
- bias[i+43] = -1.5;
- bias[i+51] = -0.5;
- bias[i+59] = -0.5;
- }
- for(i = 0; i < N; i++)
- { bias[i] *= SCALE;
- for(j = 0; j < N; j++)
- w[i][j] *= SCALE;
- }
- #ifdef DEBUG
- for(i = 0; i < N; i++)
- {
- for(j = 0; j < N; j++)
- printf("%2.0f",w[i][j]);
- printf("%7.2f\n",bias[i]);
- }
- #endif
- }
-
- randint(n)
- int n;
- /* return a random integer in the range 0 to n-1 */
- {
- return(rand() % n);
- }
-
- #define MAXSIZE 5
- boxes(a,n)
- float a[];
- int n;
- /* Draw boxes proportional to activation levels (a) ala Hinton diagrams.
- * If n equals N then draw all N boxes otherwise draw only the nth.
- */
- {
- int i,j,k,x,y,x0,y0;
- int size,count;
-
- x0 = 5;
- y0 = 40;
- count = -1;
- for(k = 0; k < 3; k++)
- { x = x0;
- y = y0;
- for(i = 0; i < 3; i++)
- { for(j = 0; j < 3; j++)
- { x += 12;
- count++;
- if(n == N || n == count)
- { size = a[count]*MAXSIZE;
- _setcolor(0);
- _rectangle(_GFILLINTERIOR,
- x-MAXSIZE,y-MAXSIZE,x+MAXSIZE,y+MAXSIZE);
- _setcolor(15);
- _rectangle(_GBORDER,x-size,y-size,x+size,y+size);
- }
- }
- x = x0;
- y += 12;
- }
- x0 += 48;
- }
- y0 = 40;
- for(k = 0; k < 5; k++)
- { x = x0;
- y = y0;
- for(i = 0; i < 3; i++)
- { for(j = 0; j < 3; j++)
- { x += 12;
- if(i != 1 || j != 1)
- { count++;
- if(n == N || n == count)
- { size = a[count]*MAXSIZE;
- _setcolor(0);
- _rectangle(_GFILLINTERIOR,
- x-MAXSIZE,y-MAXSIZE,x+MAXSIZE,y+MAXSIZE);
- _setcolor(15);
- _rectangle(_GBORDER,x-size,y-size,x+size,y+size);
- }
- }
- }
- x = x0;
- y += 12;
- }
- x0 += 48;
- }
- }
-
- drawboard()
- { static char board[5][6] = {32,179,32,179,32,0,
- 196,197,196,197,196,0,
- 32,179,32,179,32,0,
- 196,197,196,197,196,0,
- 32,179,32,179,32,0};
- int i;
- _clearscreen(_GCLEARSCREEN);
- for(i = 0; i < 5; i++)
- { _settextposition(i+8,37);
- _outtext(&board[i][0]);
- }
- _settextposition(2,2);
- _outtext("move x o empty 2x 2o 1x 1o");
- _settextposition(19,5);
- _outtext("Use arrow keys to move cursor.");
- _settextposition(20,5);
- _outtext("ENTER will change the marker under the cursor. x is program, o is opponent.");
- _settextposition(21,5);
- _outtext("ESCAPE will start network.");
- _settextposition(22,5);
- _outtext("After network is started, any key will stop.");
- _settextposition(23,5);
- _outtext("ESCAPE while network is running will exit program");
- }
-
- putmarkers(b,x)
- float b[]; /* board description vector for input to network */
- int x; /* location of programs new move */
- /*
- * puts x's and o's on the board
- * x is the programs marker,
- * o is the opponents marker
- */
- { int i,row,col;
- static int board[9] = {0};
- int c, c1;
- /* place the programs new move on the board */
- if(x > -1)
- { _settextposition(8+2*(x/3),37+2*(x%3));
- _outtext("x");
- board[x] = 1;
- }
- /* get the users input to the new board description */
- row = 8;
- col = 37;
- i = 0;
- _settextposition(row,col);
- _displaycursor(_GCURSORON);
- while((c = getch()) != 27) /* continue until escape is hit */
- { switch(c)
- { case 13: /* enter key */
- { board[i] = (board[i]+1)%3;
- if(board[i] == 0)
- _outtext(" ");
- else if(board[i] == 1)
- _outtext("x");
- else
- _outtext("o");
- _settextposition(row,col);
- break;
- }
- case 0:
- { c1 = getch();
- switch(c1)
- { case 72: /* up arrow */
- { if(row > 8)
- { row -= 2;
- i -= 3;
- _settextposition(row,col);
- break;
- }
- }
- case 75: /* left arrow */
- { if(col > 37)
- { col -= 2;
- i--;
- _settextposition(row,col);
- break;
- }
- }
- case 77: /* right arrow */
- { if(col < 41)
- { col += 2;
- i++;
- _settextposition(row,col);
- break;
- }
- }
- case 80: /* down arrow */
- { if(row < 12)
- { row += 2;
- i += 3;
- _settextposition(row,col);
- break;
- }
- }
- }
- }
- }
- }
- _displaycursor(_GCURSOROFF);
- for(i = 0; i < 9; i++)
- { switch(board[i])
- { case 0:
- { b[i] = 0.0;
- b[i+9] = 0.0;
- break;
- }
- case 1:
- { b[i] = 1.0;
- b[i+9] = 0.0;
- break;
- }
- case 2:
- { b[i] = 0.0;
- b[i+9] = 1.0;
- break;
- }
- }
- }
- }
- case 2:
- { b[i] = 0.0;
- b[i+9] = 1.0;
- break;
- }
- t n;
- /* Draw boxes proportional to activation levels (a) ala Hinton diagrams.
- * If n equals N then draw all N boxes otherwise draw only the nth.
- */
- {
- int i,j,k,x,y,x0,y0;
- int size,count;
-
- x0 = 5;
- y0 = 40;
- count = -1;
- for(k = 0; k < 3; k++)
- { x = x0;
- y = y0;
- for(i = 0; i < 3; i++)
- { for(j = 0; j < 3; j++)
- { x += 12;
- count++;
- if(n == N || n == count)
- { size = a[count]*MAXSIZE;
- _setcolor(0);
- _rectangle(_GFILLINTERIOR,
- x-MAXSIZE,y-MAXSIZE,x+MAXSIZE,y+MAXSIZE);
- _setcolor(15);
- _rectangle(_GBORDER,x-size,y-size,x+size,y+size);
- }
- }
- x = x0;
-